package com.javasm.boot.oauth2.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.javasm.boot.oauth2.entity.*;
import com.javasm.boot.oauth2.entity.vo.UserInfoVO;
import com.javasm.boot.oauth2.entity.vo.UserVO;
import com.javasm.boot.oauth2.exception.MyException;
import com.javasm.boot.oauth2.mapper.*;
import com.javasm.boot.oauth2.service.IUserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息 服务实现类
 * </p>
 *
 * @author modebing
 * @since 2022-12-13
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, OauthUser> implements IUserService, UserDetailsService {

    private final UserMapper userMapper;

    private final PermissionMapper permissionMapper;

    private final RoleMapper roleMapper;


    private final UserRoleMapper userRoleMapper;

    private final RolePermissionMapper rolePermissionMapper;

    private final RestTemplate restTemplate;

    @Value("${oauth.url}")
    private String tokenUrl;

    @Value("${inner.secret}")
    private String scecret;

    @Value("${inner.id}")
    private String id;

    @Value("${inner.passwordType}")
    private String passwordType;

    @Value("${inner.refreshTokenType}")
    private String refreshTokenType;

    public UserServiceImpl(UserMapper userMapper, PermissionMapper permissionMapper, RoleMapper roleMapper,
                           UserRoleMapper userRoleMapper, RolePermissionMapper rolePermissionMapper, RestTemplate restTemplate) {
        this.userMapper = userMapper;
        this.permissionMapper = permissionMapper;
        this.roleMapper = roleMapper;
        this.userRoleMapper = userRoleMapper;
        this.rolePermissionMapper = rolePermissionMapper;
        this.restTemplate = restTemplate;
    }

    /**
     * 认证登录接口
     *
     * @param username username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        // 根据用户名查询用户信息
        LambdaQueryWrapper<OauthUser> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(OauthUser::getUsername, username);
        OauthUser user = userMapper.selectOne(userLambdaQueryWrapper);

        //不用写sql的联表查询
        List<Permission> permissions = permissionMapper.selectJoinList(Permission.class, new MPJLambdaWrapper<Permission>()
                //selectAll查询指定实体类的全部字段
                //.selectAll(Permission.class)
                //select ：查询指定的字段
                .select(Permission::getName)
                //selectAs 查询别名
                //.selectAs
                //        leftJoin左连接,其中第一个参数是参与联表的表对应的实体类，
                //        第二个参数是这张表联表的ON字段，
                //        第三个参数是参与联表的ON的另一个实体类属性
                .leftJoin(RolePermission.class, RolePermission::getPermissionId, Permission::getId)
                .leftJoin(UserRole.class, UserRole::getRoleId, RolePermission::getRoleId)
                .leftJoin(OauthUser.class, OauthUser::getId, UserRole::getUserId)
                .eq(OauthUser::getId, user.getId()));


        //// 将查询出来的权限信息封装到用户信息当中
        user.setPermissions(permissions);
        //
        //// 返回给Security
        return user;
    }


    /**
     * @param userVO us
     * @return
     */
    @Override
    public Response innerLogin(UserVO userVO) {
        SystemUserInfo userInfo = new SystemUserInfo();
        if (StringUtils.hasText(userVO.getRefreshToken())) {
            userInfo.setRefreshToken(userVO.getRefreshToken());
            userInfo.setType(refreshTokenType);

        }else if(StringUtils.hasText(userVO.getUsername())&&StringUtils.hasText(userVO.getPassword())){
            userInfo.setUserName(userVO.getUsername());
            userInfo.setPassword(userVO.getPassword());
            userInfo.setType(passwordType);
        }else {
            throw new MyException("username or password is null");
        }
        userInfo.setClientSecret(scecret);
        userInfo.setClientId(id);
        return this.login(userInfo);
    }


    /**
     * 通用登录service
     *
     * @param userInfo oauthUser
     * @return
     */
    @Override
    public Response login(SystemUserInfo userInfo) {
        // 创建post请求,表单提交
        //List<BasicNameValuePair> body= new ArrayList<>();
        //body.add(new BasicNameValuePair("grant_type", userInfo.getType()));
        //body.add(new BasicNameValuePair("username", userInfo.getUserName()));
        //body.add(new BasicNameValuePair("password", userInfo.getPassword()));
        //body.add(new BasicNameValuePair("client_id", userInfo.getClientId()));
        //body.add(new BasicNameValuePair("client_secret", userInfo.getClientSecret()));
        //String responseStr = null;
        //try {
        //    responseStr = Request.Post(tokenUrl).bodyForm(body).execute().returnContent().asString(StandardCharsets.UTF_8);
        //} catch (Exception e) {
        //    throw new MyException("登录信息错误"+e.getMessage());
        //}
        //JSONObject resp = JSONObject.parseObject(responseStr, JSONObject.class);
        //return new Response().data(resp).code(HttpStatus.OK).msg("获取token成功");

        try {
            HttpHeaders headers = new HttpHeaders();
            headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
            MultiValueMap paramsMap = new LinkedMultiValueMap();
            paramsMap.add("flag", "1");
            paramsMap.add("grant_type", userInfo.getType());
            paramsMap.add("username", userInfo.getUserName());
            paramsMap.add("password", userInfo.getPassword());
            paramsMap.add("client_id", userInfo.getClientId());
            paramsMap.add("client_secret", userInfo.getClientSecret());
            paramsMap.add("refresh_token", userInfo.getRefreshToken());

            ResponseEntity<JSONObject> responseData = restTemplate.postForEntity(tokenUrl, new HttpEntity<>(paramsMap, headers), JSONObject.class);

            return new Response().code(HttpStatus.OK).msg("获取token成功").data(responseData.getBody());
        } catch (Throwable e) {
            throw new MyException("登陆失败，details:"+e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response insertUserInfo(UserInfoVO userVO) {
        //先查询存不存在

        // 插入用户信息
        OauthUser user = userVO.getUser();
        LambdaQueryWrapper<OauthUser> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(OauthUser::getUsername,user.getUsername());
        OauthUser oauthUser = userMapper.selectOne(userLambdaQueryWrapper);
        if (Objects.nonNull(oauthUser)){
            throw new MyException("用户已存在,请重新输入");
        }
        userMapper.insert(user);

        // 插入角色信息
        List<Role> role = userVO.getRole();
        List<Integer> roleIds = new ArrayList<>();
        LambdaQueryWrapper<Role> roleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roleLambdaQueryWrapper.in(Role::getName,role.stream().map(Role::getName).collect(Collectors.toList()));
        List<Role> rolesByDb = roleMapper.selectList(roleLambdaQueryWrapper);
        for (Role role1 : rolesByDb) {
            roleIds.add(role1.getId());
        }
        List<Role> roles = role.stream().filter(item -> rolesByDb.stream().noneMatch(role1 -> role1.getName().equals(item.getName()))).collect(Collectors.toList());
        for (Role role1 : roles) {
            roleMapper.insert(role1);
            roleIds.add(role1.getId());
        }
        for (Integer roleId : roleIds) {
            UserRole userRole = new UserRole();
            userRole.setUserId(Math.toIntExact(user.getId()));
            userRole.setRoleId(roleId);
            userRoleMapper.insert(userRole);
        }

        // 插入用户权限
        List<Permission> permissions = userVO.getPermissions();
        List<Integer> ids = new ArrayList<>();
        LambdaQueryWrapper<Permission> permissionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        permissionLambdaQueryWrapper.in(Permission::getName,permissions.stream().map(Permission::getName).collect(Collectors.toList()));
        List<Permission> permissionList = permissionMapper.selectList(permissionLambdaQueryWrapper);

        List<Permission> collect = permissions.stream().
                filter(item -> permissionList.stream().noneMatch(permission -> item.getName().equals(permission.getName()))).collect(Collectors.toList());
        for (Permission permission : collect) {
            permissionMapper.insert(permission);
            ids.add(permission.getId());
        }



        return null;
    }


}
